
#include <stdio.h>
#include "ffrtmp.h"

typedef struct {
	FILE *fp_data;
	FILE *fp_meta;
	char extradata[64];// H264 SPS/PPS data
	int extrasize;
} Stream_Entity;
int h264_read_func(void *ctx,char *frame,int size,int64_t *pts,int *keyflag)
{
	static int64_t start_pts = 0;

	if(ctx==NULL)
		return -1;

	Stream_Entity *entity = (Stream_Entity*)ctx;
	FILE *fp = entity->fp_data;
	FILE *fp_meta = entity->fp_meta;
	int frmsize = 0;

	if(entity->extradata==NULL || entity->extrasize<=0)
	{//read SPS/PPS data for decoder
		frmsize = entity->extrasize = fread(entity->extradata,1,44,fp);
		rewind(fp);
		return frmsize;
	}
	else if(frame==NULL || size <= 0)
		return -1;

	char meta[1024];
	int num,ts,flag;
	if(fgets(meta,sizeof(meta),fp_meta)==NULL)
		return -1;
	num = sscanf(meta,"Time:%d, data size:%d, flag:%d",&ts,&frmsize,&flag);
	if(num != 3)
	{
		printf("sscanf meta attr fail,num = %d\n",num);
		return -1;
	}
	printf("264 frame size = %d,ts: %d,flag: %d\n",frmsize,ts,flag);
	if(size < frmsize)
	{
		printf("buf size %d < frmsize %d\n",size,frmsize);
		return -1;
	}
	num = fread(frame,1,frmsize,fp);
	if(num != frmsize)
	{
		printf("read video frame ret = %d != frmsize %d\n",num,frmsize);
		return -1;
	}
	if(pts)
	{
		if(start_pts == 0)
		{
			start_pts = ts;
			*pts = 0;
		}
		else
		{
			*pts = ts - start_pts;
		}
	}
	if(keyflag)
	{
		*keyflag = flag;
	}
	return frmsize;
}

int g711_read_func(void *ctx,char *frame,int size,int64_t *pts,int *keyflag)
{
	#define G711_NUM 320
	if(ctx==NULL||frame==NULL||size<G711_NUM)
		return -1;

	FILE *fp = (FILE *)ctx;
	int pcmaSize = 0;
	pcmaSize = fread(frame,1,G711_NUM,fp);
	if(pcmaSize != G711_NUM)
	{
		rewind(fp);
		pcmaSize = fread(frame,1,G711_NUM,fp);
	}
	//printf("G711 Size = %d\n",pcmaSize);
	return pcmaSize;
}

int main(int argc, char* argv[])
{
	if(argc >= 2 && (strcmp(argv[1],"-h")==0 || strcmp(argv[1],"--help")==0))
	{
		printf("usage: %s <rtmp-url> <enable-audio:0|1> <audio-enc:aac|g711>\n\n",argv[0]);
		exit(EXIT_SUCCESS);
	}

	ff_rtmp_ctx myctx;

	int ret;
	char outurl[512]={0};
	const char *in_filename = NULL, *out_filename = NULL, *audio_filename = NULL;
	const char *video_datfile = NULL,*audio_datfile = NULL;
	FILE *fp_g711 = NULL;

	in_filename  = "data/video.h264";
	video_datfile = "data/video.dat";//H264 MetaData File

	if(argc >= 3 && atoi(argv[2])==0) {// 不推音频
		audio_filename = NULL;
		audio_datfile = NULL;
	} else {
		if(argc >= 4 && strcmp(argv[3],"aac")==0) {
			//audio_filename = "data/audio.aac"; // vlc: stereo, 16000HZ, 32bits
			//audio_filename = "data/test.aac"; // vlc: stereo, 44100HZ, 32bits
			audio_datfile = "data/audio.dat";//AAC  MetaData File
		} else {
			audio_filename = "data/test.g711a"; // mono, 8000HZ, 16bits
		}
	}

	if(argc >= 2) {
		strcpy(outurl,argv[1]);
		out_filename = outurl;
	} else {
		//out_filename = "rtmp://localhost/publishlive/livestream";//输出 URL（Output URL）[RTMP]
		out_filename = "rtmp://www.wmatrix.net/ipc/ffmpeg";//输出 URL（Output URL）[RTMP]
	}

	Stream_Entity h264_entity = {0,0,0,0}, aac_entity={0,0,0,0};
	if(video_datfile && strstr(in_filename,".h264"))
	{
		h264_entity.fp_data = fopen(in_filename,"rb");
		h264_entity.fp_meta = fopen(video_datfile,"rb");
		if(h264_entity.fp_data==NULL || h264_entity.fp_meta==NULL)
		{
			printf("fopen h264 file %s fail\n",in_filename);
			exit(EXIT_FAILURE);
		}
	}
	if(audio_datfile && audio_filename && strstr(audio_filename,"aac"))
	{
		aac_entity.fp_data = fopen(audio_filename,"rb");
		aac_entity.fp_meta = fopen(audio_datfile,"rb");
		if(aac_entity.fp_data==NULL||aac_entity.fp_meta==NULL)
		{
			printf("fopen aac file %s fail!\n",audio_filename);
			exit(EXIT_FAILURE);
		}
	}
	else if(audio_filename && (strstr(audio_filename,".g711a") || strstr(audio_filename,".pcma")))
	{
		fp_g711 = fopen(audio_filename,"rb");
		if(fp_g711==NULL)
		{
			printf("fopen audio file %s fail!\n",audio_filename);
			exit(EXIT_FAILURE);
		}
	}

	ret = ff_init_rtmp(&myctx,out_filename);
	if(ret < 0)
	{
		printf("ff_init_rtmp fail ret = %d\n",ret);
		exit(EXIT_FAILURE);
	}

	//Add Video Streams
	if(h264_entity.fp_data && h264_entity.fp_meta)
	{
		h264_entity.extrasize = fread(h264_entity.extradata,1,44,h264_entity.fp_data);
		rewind(h264_entity.fp_data);
		if((ret==ff_add_264_stream(&myctx,1280,720,25,768,h264_entity.extradata,h264_entity.extrasize,&h264_entity,h264_read_func))<0)
			goto end;
	}
	else if ((ret = ff_add_streams_from_file(&myctx, in_filename)) < 0) {
		goto end;
	}

	//Add Audio Stream if there is no one
	if(myctx.ofmt_ctx->nb_streams == 1)
	{
		if(fp_g711)
		{
			if((ret=ff_add_pcma_stream(&myctx,1,8000,16,fp_g711,g711_read_func)<0))
				goto end;
		}
		else if(aac_entity.fp_data && aac_entity.fp_meta)
		{
			if((ret=ff_add_aac_stream(&myctx,2,16000,32,&aac_entity,NULL)<0))
				goto end;
		}
		else if (audio_filename && (ret = ff_add_streams_from_file(&myctx,audio_filename)) < 0) {
			goto end;
		}
	}

	ret = ff_start_rtmp(&myctx);
	if(ret < 0)
	{
		printf("ff_start_rtmp fail ret = %d\n",ret);
		goto end;
	}

	int got_size = 0;
	while (1)
	{
		ret=ff_write_rtmp_frame(&myctx, &got_size);
		if(ret < 0)
		{
			break;
		}
		else if(ret == 0 && got_size == 0)
		{// read data empty, wait data
			av_usleep(10*1000);
		}
	}
	ff_stop_rtmp(&myctx);

end:
	if(fp_g711)
	{
		fclose(fp_g711);
		fp_g711 = NULL;
	}
	if(h264_entity.fp_data) { fclose(h264_entity.fp_data); }
	if(h264_entity.fp_meta) { fclose(h264_entity.fp_meta); }
	if(aac_entity.fp_data) { fclose(aac_entity.fp_data); }
	if(aac_entity.fp_meta) { fclose(aac_entity.fp_meta); }

	ff_exit_rtmp(&myctx);
	return 0;
}

